package com.alihealth.client.view.loading;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.annotation.ColorInt;
import android.support.annotation.DrawableRes;
import android.support.v4.widget.NestedScrollView;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ScrollView;
import android.widget.TextView;

/**
 * For page loading state changed.
 * demo: http://gitlab.alibaba-inc.com/wupuquan.wpq/alihealth-loading-android/tree/master
 *
 * @author wpq
 * @version 1.0
 */
public class LoadingController implements LoadingInterface {
    private static final String TAG = LoadingController.class.getSimpleName();

    private final View loadingTargetView;

    @ColorInt
    private int bgColor;
    private LoadingInterface.OnClickListener onErrorRetryClickListener;
    private LoadingInterface.OnClickListener onEmptyTodoClickListener;

    private LayoutInflater inflater;
    private ViewGroup parentView;
    private int currentViewIndex;
    private ViewGroup.LayoutParams targetViewParams;

    private View loadingView;
    private ImageView ivLoading;

    private View networkErrorView;

    private View errorView;
    private TextView tvError;
    private TextView tvErrorRetry;

    private View emptyView;
    private ImageView ivEmpty;
    private TextView tvEmpty;
    private TextView tvEmptyTodo;

    private boolean isLoading = true;

    private final LoadingConfigInterface loadingConfig;

    public static LoadingController create(View loadingTargetView, LoadingConfigInterface loadingConfig) {
        return new LoadingController(loadingTargetView, loadingConfig);
    }

    private LoadingController(View loadingTargetView, LoadingConfigInterface loadingConfig) {
        this.loadingTargetView = loadingTargetView;
        this.loadingConfig = loadingConfig;
        checkArguments();
        init();
    }

    private void checkArguments() {
        if (loadingTargetView == null) {
            throw new IllegalArgumentException("loadingTargetView can not be null!");
        }
        if (loadingConfig == null) {
            throw new IllegalArgumentException("loadingConfig can not be null!");
        }
    }

    private void init() {
        inflater = LayoutInflater.from(loadingTargetView.getContext());
        targetViewParams = loadingTargetView.getLayoutParams();
        if (loadingTargetView.getParent() != null) {
            parentView = (ViewGroup) loadingTargetView.getParent();
        } else {
            parentView = loadingTargetView.getRootView().findViewById(android.R.id.content);
        }
        int count = parentView.getChildCount();
        for (int i = 0; i < count; i++) {
            if (loadingTargetView == parentView.getChildAt(i)) {
                currentViewIndex = i;
                break;
            }
        }
    }

    public LoadingController setBgColor(@ColorInt int color) {
        this.bgColor = color;
        return this;
    }

    public LoadingController setOnErrorRetryClickListener(LoadingInterface.OnClickListener listener) {
        this.onErrorRetryClickListener = listener;
        return this;
    }

    public LoadingController setOnEmptyTodoClickListener(LoadingInterface.OnClickListener listener) {
        this.onEmptyTodoClickListener = listener;
        return this;
    }

    @Override
    public void showLoading() {
        showLoading(0, null, null);
    }

    @Override
    public void showLoading(@DrawableRes int loadingImageResource) {
        showLoading(loadingImageResource, null, null);
    }

    @Override
    public void showLoading(Drawable loadingImageDrawable) {
        showLoading(0, loadingImageDrawable, null);
    }

    @Override
    public void showLoading(View customView) {
        showLoading(0, null, customView);
    }

    /**
     * 显示Loading页面
     *
     * @param loadingImageResource Loading提示图片资源id
     * @param loadingImageDrawable Loading提示图片资源
     * @param customView           自定义页面
     */
    @SuppressWarnings("ConstantConditions")
    @SuppressLint("InflateParams")
    private void showLoading(@DrawableRes int loadingImageResource, Drawable loadingImageDrawable, View customView) {
        if (customView != null) {
            loadingView = customView;
            showView(loadingView);
            return;
        }

        initLoadingView();
        if (loadingView == null) {
            return;
        }

        // Loading图片
        if (ivLoading != null) {
            if (loadingImageResource != 0) {
                ivLoading.setImageResource(loadingImageResource);
            } else if (loadingImageDrawable != null) {
                ivLoading.setImageDrawable(loadingImageDrawable);
            }
        }

        showView(loadingView);
    }

    private void initLoadingView() {
        if (loadingConfig.getLoadingLayoutId() == 0) {
            return;
        }
        if (loadingView == null) {
            loadingView = inflater.inflate(loadingConfig.getLoadingLayoutId(), null);
        }
        if (loadingView == null) {
            return;
        }

        View vLoadingImage = loadingView.findViewById(loadingConfig.getLoadingImageViewId());
        if (vLoadingImage instanceof ImageView) {
            ivLoading = (ImageView) vLoadingImage;
        }
    }

    @Override
    public void showError() {
        showError("");
    }

    @Override
    public void showError(String errorMessage) {
        showError(errorMessage, true);
    }

    @Override
    public void showError(String errorMessage, boolean showRetryButton) {
        showError(errorMessage, showRetryButton, "", null);
    }

    @Override
    public void showError(String errorMessage, String retryButtonText) {
        showError(errorMessage, true, retryButtonText, null);
    }

    @Override
    public void showError(View customView) {
        showError("", true, "", customView);
    }

    /**
     * 显示错误提示页面
     *
     * @param errorMessage    错误信息
     * @param showRetryButton 是否显示重试按钮
     * @param retryButtonText 重试按钮的文字
     * @param customView      自定义页面
     */
    @SuppressLint("InflateParams")
    private void showError(String errorMessage, boolean showRetryButton, String retryButtonText, View customView) {
        // 网络错误
        if (!isNetworkConnected(loadingTargetView.getContext())) {
            showNetworkError();
            return;
        }

        // 其他错误
        if (customView != null) {
            errorView = customView;
            showView(errorView);
            return;
        }

        initErrorView();
        if (errorView == null) {
            return;
        }

        // 提示文字
        if (tvError != null) {
            if (!TextUtils.isEmpty(errorMessage)) {
                tvError.setText(errorMessage);
            }
        }

        // 重试
        if (tvErrorRetry != null) {
            if (showRetryButton) {
                tvErrorRetry.setVisibility(View.VISIBLE);
                if (!TextUtils.isEmpty(retryButtonText)) {
                    tvErrorRetry.setText(retryButtonText);
                }
            } else {
                tvErrorRetry.setVisibility(View.GONE);
            }
        }

        showView(errorView);
    }

    private void initErrorView() {
        if (loadingConfig.getErrorLayoutId() == 0) {
            return;
        }
        if (errorView == null) {
            errorView = inflater.inflate(loadingConfig.getErrorLayoutId(), null);
        }
        if (errorView == null) {
            return;
        }

        // 提示文字
        View vErrorMessage = errorView.findViewById(loadingConfig.getErrorTextViewId());
        if (vErrorMessage instanceof TextView) {
            tvError = (TextView) vErrorMessage;
        }

        // 重试
        // 如果有重试按钮，则点击重试按钮执行刷新
        View vRetry = errorView.findViewById(loadingConfig.getErrorRetryViewId());
        if (vRetry != null) {
            vRetry.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (onErrorRetryClickListener != null) {
                        onErrorRetryClickListener.onClick(v);
                    }
                }
            });
            // 重试按钮文字
            if (vRetry instanceof TextView) {
                tvErrorRetry = (TextView) vRetry;
            }
        } else { // 如果没有重试按钮，则点击整个错误页面执行刷新
            setErrorRootViewClick(errorView, new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (onErrorRetryClickListener != null) {
                        onErrorRetryClickListener.onClick(v);
                    }
                }
            });
        }
    }

    /**
     * 显示网络错误页面
     */
    private void showNetworkError() {
        if (networkErrorView != null) {
            showView(networkErrorView);
            return;
        }

        initNetworkErrorView();
        if (networkErrorView == null) {
            return;
        }

        showView(networkErrorView);
    }

    private void initNetworkErrorView() {
        if (loadingConfig.getNetworkErrorLayoutId() == 0) {
            return;
        }
        if (networkErrorView == null) {
            networkErrorView = inflater.inflate(loadingConfig.getNetworkErrorLayoutId(), null);
        }
        if (networkErrorView == null) {
            return;
        }

        // 如果有重试按钮，则点击重试按钮执行刷新
        View vRetry = networkErrorView.findViewById(loadingConfig.getNetworkErrorRetryViewId());
        if (vRetry != null) {
            vRetry.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (onErrorRetryClickListener != null) {
                        onErrorRetryClickListener.onClick(v);
                    }
                }
            });
        } else { // 如果没有重试按钮，则点击整个错误页面执行刷新
            setErrorRootViewClick(networkErrorView, new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (onErrorRetryClickListener != null) {
                        onErrorRetryClickListener.onClick(v);
                    }
                }
            });
        }
    }

    /**
     * 错误布局点击事件处理，如果错误布局上没有可点击按钮，则点整个布局触发重试，
     * 如果错误布局根布局为ScrollView或NestedScrollView，则需要为其子View设置点击事件
     *
     * @param errorRootView 错误布局根布局
     */
    private void setErrorRootViewClick(View errorRootView, View.OnClickListener onClickListener) {
        try {
            if (errorRootView instanceof ScrollView || errorRootView instanceof NestedScrollView) {
                ((ViewGroup) errorRootView).getChildAt(0).setOnClickListener(onClickListener);
            } else {
                errorRootView.setOnClickListener(onClickListener);
            }
        } catch (Exception e) {
//            e.printStackTrace();
            Log.e(TAG, "setErrorRootViewClick exception: " + e.getMessage());
        }
    }

    @Override
    public void showEmpty() {
        showEmpty("");
    }

    @Override
    public void showEmpty(String emptyMessage) {
        showEmpty(emptyMessage, "");
    }

    @Override
    public void showEmpty(String emptyMessage, String todoButtonText) {
        showEmpty(0, emptyMessage, todoButtonText);
    }

    @Override
    public void showEmpty(@DrawableRes int emptyImageResource, String emptyMessage) {
        showEmpty(emptyImageResource, emptyMessage, "");
    }

    @Override
    public void showEmpty(@DrawableRes int emptyImageResource, String emptyMessage, String todoButtonText) {
        showEmpty(emptyImageResource, null, emptyMessage, todoButtonText, null);
    }

    @Override
    public void showEmpty(Drawable emptyImageDrawable, String emptyMessage) {
        showEmpty(emptyImageDrawable, emptyMessage, "");
    }

    @Override
    public void showEmpty(Drawable emptyImageDrawable, String emptyMessage, String todoButtonText) {
        showEmpty(0, emptyImageDrawable, emptyMessage, todoButtonText, null);
    }

    @Override
    public void showEmpty(View customView) {
        showEmpty(0, null, "", "", customView);
    }

    /**
     * 显示空数据提示页面
     *
     * @param emptyImageResource 空数据提示图片资源id
     * @param emptyImageDrawable 空数据提示图片资源
     * @param emptyMessage       空数据信息
     * @param todoButtonText     Todo按钮的文字
     * @param customView         自定义页面
     */
    @SuppressWarnings("ConstantConditions")
    @SuppressLint("InflateParams")
    private void showEmpty(@DrawableRes int emptyImageResource, Drawable emptyImageDrawable, String emptyMessage, String todoButtonText, View customView) {
        if (customView != null) {
            emptyView = customView;
            showView(emptyView);
            return;
        }

        initEmptyView();
        if (emptyView == null) {
            return;
        }

        // 空数据提示图片
        if (ivEmpty != null) {
            if (emptyImageResource != 0) {
                ivEmpty.setImageResource(emptyImageResource);
            } else if (emptyImageDrawable != null) {
                ivEmpty.setImageDrawable(emptyImageDrawable);
            }
        }

        // 空数据提示文字
        if (tvEmpty != null) {
            if (!TextUtils.isEmpty(emptyMessage)) {
                tvEmpty.setText(emptyMessage);
            }
        }

        // 空数据Todo按钮
        if (tvEmptyTodo != null) {
            if (!TextUtils.isEmpty(todoButtonText)) {
                tvEmptyTodo.setVisibility(View.VISIBLE);
                tvEmptyTodo.setText(todoButtonText);
            } else {
                tvEmptyTodo.setVisibility(View.GONE);
            }
        }

        showView(emptyView);
    }

    private void initEmptyView() {
        if (loadingConfig.getEmptyLayoutId() == 0) {
            return;
        }
        if (emptyView == null) {
            emptyView = inflater.inflate(loadingConfig.getEmptyLayoutId(), null);
        }
        if (emptyView == null) {
            return;
        }

        // 空数据提示图片
        View vEmptyImage = emptyView.findViewById(loadingConfig.getEmptyImageViewId());
        if (vEmptyImage instanceof ImageView) {
            ivEmpty = (ImageView) vEmptyImage;
        }

        // 空数据提示文字
        View vEmptyMessage = emptyView.findViewById(loadingConfig.getEmptyTextViewId());
        if (vEmptyMessage instanceof TextView) {
            tvEmpty = (TextView) vEmptyMessage;
        }

        // 空数据Todo按钮
        View vTodo = emptyView.findViewById(loadingConfig.getEmptyTodoViewId());
        if (vTodo != null) {
            vTodo.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (onEmptyTodoClickListener != null) {
                        onEmptyTodoClickListener.onClick(v);
                    }
                }
            });
            // Todo按钮文字
            if (vTodo instanceof TextView) {
                tvEmptyTodo = (TextView) vTodo;
            }
        }
    }

    @Override
    public void showTarget() {
        showView(loadingTargetView);
    }

    /**
     * 切换状态
     *
     * @param view 目标View
     */
    private void showView(View view) {
        if (view == null || parentView.getChildAt(currentViewIndex) == view) {
            return;
        }

        if (bgColor != 0 && loadingTargetView != view) {
            view.setBackgroundColor(bgColor);
        }

        // 先把view从父布局移除
        ViewGroup viewParent = (ViewGroup) view.getParent();
        if (viewParent != null) {
            viewParent.removeView(view);
        }

        // 移除当前位置的View
        parentView.removeViewAt(currentViewIndex);
        if (loadingTargetView == view) {
            loadingTargetView.setVisibility(View.VISIBLE);
            parentView.addView(loadingTargetView, currentViewIndex, targetViewParams);
        } else {
            // 1.如果要展示的是loading、error或empty，移除targetView后在原位置先加一个FrameLayout，
            //   然后把targetView加在FrameLayout底部，其他状态View加在targetView上面，这样做的目的是
            //   防止移除targetView导致findView空指针
            // 2.考虑有些页面Loading的父布局是CoordinatorLayout，为了保证可以滑动，在FrameLayout外面
            //   再套一层NestedScrollView
            NestedScrollView nestedScrollView = new NestedScrollView(loadingTargetView.getContext());
            nestedScrollView.setFillViewport(true);
            parentView.addView(nestedScrollView, currentViewIndex, targetViewParams);

            NestedScrollView.LayoutParams nestedLayoutParams = new NestedScrollView.LayoutParams(NestedScrollView.LayoutParams.MATCH_PARENT, NestedScrollView.LayoutParams.MATCH_PARENT);
            FrameLayout newParent = new FrameLayout(loadingTargetView.getContext());
            nestedScrollView.addView(newParent, nestedLayoutParams);

            FrameLayout.LayoutParams newParentParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
            ViewGroup targetParent = (ViewGroup) loadingTargetView.getParent();
            if (targetParent != null) {
                targetParent.removeView(loadingTargetView);
            }
            newParent.addView(loadingTargetView, 0, newParentParams);
            loadingTargetView.setVisibility(View.GONE);
            newParent.addView(view, 1, newParentParams);
            view.setClickable(true); // 防止事件穿透
            view.setFocusable(true);
        }

        isLoading = view == loadingView;
        if (ivLoading != null) {
            Drawable drawable = ivLoading.getDrawable();
            if (drawable instanceof AnimationDrawable) {
                // Loading图片帧动画
                AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
                if (isLoading) {
                    animationDrawable.start();
                } else {
                    animationDrawable.stop();
                }
            }
        }
    }

    @Override
    public boolean isLoading() {
        return isLoading;
    }

    /**
     * 判断网络是否连接
     */
    private boolean isNetworkConnected(Context context) {
        try {
            @SuppressLint("MissingPermission")
            NetworkInfo info = ((ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
            return info != null && info.isConnected();
        } catch (Exception e) {
//            e.printStackTrace();
        }
        return false;
    }

    /**
     * View替换
     *
     * @param src    源View
     * @param target 目标View
     */
    private void replaceView(View src, View target) {
        ViewGroup targetParent = (ViewGroup) target.getParent();
        if (targetParent != null) {
            targetParent.removeView(target);
        }

        ViewGroup srcParent = (ViewGroup) src.getParent();
        if (srcParent != null) {
            int index = -1;
            for (int i = 0; i < srcParent.getChildCount(); i++) {
                if (srcParent.getChildAt(i) == src) {
                    index = i;
                }
            }
            srcParent.removeViewAt(index);
            srcParent.addView(target, index, src.getLayoutParams());
        }
    }

}
